# -*- coding: utf-8 -*- 
# @Time : 2022/12/1 11:54 
# @Author : ZKL 
# @File : GUIServer.py

from tkinter import *
from tkinter.scrolledtext import ScrolledText
import tkinter.messagebox

import asyncio
import websockets
import _thread as thread


def break_except_ctrl_c(event):
    if (4 == event.state and event.keysym == 'c'):
        return None
    else:
        return "break"


class WS_Server_GUI:
    def __init__(self):

        # 客户端句柄
        self.CLIENTS = {}
        # 窗口
        self.root = Tk()
        self.root.title("WS_Server_GUI")
        self.root.geometry("800x600")
        self.root.resizable(width=False, height=False)

        # 上中下框架
        self.top = Frame(self.root, bg="#FFFFAF", height=60, width=800)
        self.middle = Frame(self.root, bg="#DDDDDD", height=420, width=800)
        self.bottom = Frame(self.root, bg="#AFCFFF", height=120, width=800)

        self.top.pack()
        self.top.propagate(False)
        self.middle.pack()
        self.middle.propagate(False)
        self.bottom.pack()
        self.bottom.propagate(False)

        # 上部标题
        self.top_label = Label(self.top, text="Websocket 服务端", font=("黑体", 30), fg="black", bg="#FFFFAF")
        self.top_label.pack(pady=10)

        # 中左部列表
        self.middle_left = Frame(self.middle, bg="#DDDDDD", height=420, width=300)
        self.middle_left.pack(side="left")
        self.middle_left.propagate(False)
        self.middle_left_label = Label(self.middle_left, text="在线客户端（点击选择）", font=("黑体", 15), fg="black", bg="#DDDDDD")
        self.middle_left_label.pack()
        self.client_list = Listbox(self.middle_left, height=400, width=280, font=("Arial", 15))
        self.client_list.pack(padx=5)

        # 中右部信息
        self.middle_right = Frame(self.middle, bg="#DDDDDD", height=420, width=500)
        self.middle_right.pack(side="right")
        self.middle_right.propagate(False)
        self.middle_right_label = Label(self.middle_right, text="历史消息", font=("黑体", 15), fg="black", bg="#DDDDDD")
        self.middle_right_label.pack()

        self.message_history = ScrolledText(self.middle_right, height=400, font=("Arial", 15))
        self.message_history.bind("<Key>", lambda e: break_except_ctrl_c(e))  # 屏蔽按键（Ctrl+C除外）
        self.message_history.pack(padx=5)

        # 下部发送
        self.bottom_left = Frame(self.bottom, height=100, width=600, bg="#AFCFFF")
        self.bottom_left.pack(side="left")
        self.bottom_left.propagate(False)
        self.bottom_text = Text(self.bottom_left, font=("Arial", 20))
        self.bottom_text.pack(padx=5)

        self.send_button = Button(self.bottom, text="发送", font=("黑体", 20), fg="green",
                                  command=lambda: asyncio.run(self.send()))
        self.send_button.pack(side="left", padx=10)
        self.clear_button = Button(self.bottom, text="清除", font=("黑体", 20), fg="red", command=self.clear)
        self.clear_button.pack(side="left", padx=10)

        # 启动WS服务线程
        thread.start_new_thread(self.startWS, ())

        # 启动GUI线程
        self.root.mainloop()

    def clear(self):
        self.bottom_text.delete(1.0, END)

    def add_history(self, record):
        self.message_history.insert(END, record)
        self.message_history.see(END)

    def delete_client(self, ws_client):
        c_list = self.client_list.get(0, END)
        for i in range(0, len(c_list)):
            if c_list[i] == str(ws_client.remote_address):
                self.client_list.delete(i)
                break
        self.CLIENTS.pop(str(ws_client.remote_address))

    def add_client(self, ws_client):
        self.CLIENTS.update({str(ws_client.remote_address): ws_client})
        self.client_list.insert(END, str(ws_client.remote_address))

    async def send(self):
        text = self.bottom_text.get(1.0, END)
        text = text.strip()
        index = self.client_list.curselection()
        # if not text:
        #     tkinter.messagebox.showwarning("警告", "不可发送空白信息！")
        #     return None
        if not index:
            tkinter.messagebox.showwarning("警告", "请先选择一个客户端！")
            return None

        address = self.client_list.get(index[0])
        ws_client = self.CLIENTS.get(address)

        try:
            await ws_client.send(text)
            self.clear()
            record = "Server >> " + address + ":\n" + text + "\n\n"
            self.add_history(record)
        except Exception as e2:
            print(e2)
            tkinter.messagebox.showwarning("警告", "该客户端已离线！")
            self.delete_client(ws_client)

    async def receive(self, ws_client, path):
        self.add_client(ws_client)
        try:
            async for message in ws_client:
                record = str(ws_client.remote_address) + " >> Server:\n" + message + "\n\n"
                self.add_history(record)
        except Exception as e1:
            print(e1)
            self.delete_client(ws_client)

    def startWS(self):
        # 在其他线程中，必须先手动创建event_loop，再启动WS服务。在主线程中则不必。
        new_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(new_loop)

        server = websockets.serve(self.receive, '', 8765)
        asyncio.get_event_loop().run_until_complete(server)
        asyncio.get_event_loop().run_forever()


if __name__ == "__main__":
    app = WS_Server_GUI()
